
package com.feib.stms.util;

import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;


/**
 * @title (#)UnicodeInputStream.java<br>
 * @description changed BOM recognition ordering (longer boms first)<br>
 * Original pseudocode   : Thomas Weidenfeller<br>
 * http://www.unicode.org/unicode/faq/utf_bom.html<br>
 * BOMs:<br>
 * 00 00 FE FF    = UTF-32, big-endian<br>
 * FF FE 00 00    = UTF-32, little-endian<br>
 * EF BB BF       = UTF-8,<br>
 * FE FF          = UTF-16, big-endian<br>
 * FF FE          = UTF-16, little-endian<br>
 * Win2k Notepad:<br>
 * Unicode format = UTF-16LE<br>
 * This inputstream will recognize unicode BOM marks
 * and will skip bytes if getEncoding() method is called
 * before any of the read(...) methods.<br>
 * Usage pattern:<br>
 * <code>
 * String enc = "ISO-8859-1"; // or NULL to use systemdefault<br>
 * FileInputStream fis = new FileInputStream(file);<br>
 * UnicodeInputStream uin = new UnicodeInputStream(fis, enc);<br>
 * enc = uin.getEncoding(); // check and skip possible BOM bytes<br>
 * InputStreamReader in;<br>
 * if (enc == null) in = new InputStreamReader(uin);<br>
 * else in = new InputStreamReader(uin, enc);<br>
 * </code>
 * @author Aki Nieminen<br>
 * @version 1.0.0 2010/11/25
 * @copyright Far Eastern International Bank Copyright (c) 2010<br>
 * @2010/11/24 create by Jimmy Liu<br>
 */
public class UnicodeInputStream extends InputStream {
	PushbackInputStream internalIn;
	boolean             isInited = false;
	String              defaultEnc;
	String              encoding;

	private static final int BOM_SIZE = 4;

	public UnicodeInputStream(InputStream in, String defaultEnc) {
		internalIn = new PushbackInputStream(in, BOM_SIZE);
		this.defaultEnc = defaultEnc;
	}

	public String getDefaultEncoding() {
		return defaultEnc;
	}

	public String getEncoding() {
		if (!isInited) {
			try {
				init();
			} catch (IOException ex) {
				IllegalStateException ise = new IllegalStateException("Init method failed.");
				ise.initCause(ise);
				throw ise;
			}
		}
		return encoding;
	}

	/**
	 * Read-ahead four bytes and check for BOM marks. Extra bytes are
	 * unread back to the stream, only BOM bytes are skipped.
	 */
	protected void init() throws IOException {
		if (isInited) return;

		byte bom[] = new byte[BOM_SIZE];
		int n, unread;
		n = internalIn.read(bom, 0, bom.length);

		if ( (bom[0] == (byte)0x00) && (bom[1] == (byte)0x00) &&
				(bom[2] == (byte)0xFE) && (bom[3] == (byte)0xFF) ) {
			encoding = "UTF-32BE";
			unread = n - 4;
		} else if ( (bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE) &&
				(bom[2] == (byte)0x00) && (bom[3] == (byte)0x00) ) {
			encoding = "UTF-32LE";
			unread = n - 4;
		} else if (  (bom[0] == (byte)0xEF) && (bom[1] == (byte)0xBB) &&
				(bom[2] == (byte)0xBF) ) {
			encoding = "UTF-8";
			unread = n - 3;
		} else if ( (bom[0] == (byte)0xFE) && (bom[1] == (byte)0xFF) ) {
			encoding = "UTF-16BE";
			unread = n - 2;
		} else if ( (bom[0] == (byte)0xFF) && (bom[1] == (byte)0xFE) ) {
			encoding = "UTF-16LE";
			unread = n - 2;
		} else {
			// Unicode BOM mark not found, unread all bytes
			encoding = defaultEnc;
			unread = n;
		}      


		if (unread > 0) internalIn.unread(bom, (n - unread), unread);

		isInited = true;
	}

	public void close() throws IOException {
		//init();
		isInited = true;
		internalIn.close();
	}

	public int read() throws IOException {
		//init();
		isInited = true;
		return internalIn.read();
	}


}
